/**
 * de.herberlin.sudoku.Sudoku
 */
package de.herberlin.sudoku;

import java.io.Serializable;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;

/**
 * @author herberlin
 * @created 30.05.2006
 */
public class Sudoku implements Serializable,Cloneable {

	static final long serialVersionUID = -1L;

	private transient Logger logger=null;
	/**
	 * radix is the radix of an edge radix
	 */
	private int radix=Constants.INT_NOT_SET;

	private Field[][] fields=null;
	private Group[] rows=null;
	private Group[] cols=null;
	private Group[] squares=null;
	private Group[] allGroups=null;

	/**
	 *
	 */
	public Sudoku() {
		this.radix=Constants.RADIX;
		logger=Logger.getLogger(getClass().getName());
		init();
	}

	private void init() {
		int size=radix*radix;

		rows=new Group[size];
		cols=new Group[size];
		squares=new Group[size];
		for (int i=0;i<size;i++) {
			rows[i]=new Group(Group.TYPE_ROW);
			cols[i]=new Group(Group.TYPE_COLUMN);
			squares[i]=new Group(Group.TYPE_SQUARE);
		}
		fields=new Field[size][size];

		for (int x=0;x< size;x++) {
			for (int y=0;y<size;y++) {
				fields[x][y]=FieldFactory.getInstance().getField(x,y);
				fields[x][y].setSudoku(this);
				cols[x].add(fields[x][y]);
				rows[y].add(fields[x][y]);

				int xFactor=((int)(x/radix))*radix;
				int yFactor=(int)(y/radix);
				squares[xFactor+yFactor].add(fields[x][y]);
			}
		}

		List all=new LinkedList();
		all.addAll(Arrays.asList(rows));
		all.addAll(Arrays.asList(cols));
		all.addAll(Arrays.asList(squares));
		allGroups=(Group[]) all.toArray(new Group[all.size()]);
	}


	public Field[][] getFields() {
		return fields;
	}

	public Group[] getSquares() {
		return squares;
	}

	/**
	 * Returns the conflicting fiels or null
	 * if there are no confilicts for that change
	 * @param changed
	 * @return
	 */
	public Field[] getConflictFields(Field changed) {

		List result=new LinkedList();

		for (int i=0;i<allGroups.length;i++) {
			Field conflict=allGroups[i].getConflictField(changed);
			if (conflict!=null && ! result.contains(conflict)) {
				result.add(conflict);
			}
		}
		if (result.size()==0) {
			return null;
		} else {
			return (Field[])result.toArray(new Field[result.size()]);
		}
	}

	public boolean isConflict(Field changed) {
		for (int i=0;i<allGroups.length;i++) {
			logger.fine("Checking group: "+allGroups[i]);
			Field conflict=allGroups[i].getConflictField(changed);
			if (conflict!=null) {
				logger.fine("Conflict found: type="+allGroups[i].getType()+" changed="+changed+", conflict="+conflict );
				return true;
			}
		}
		return false;
	}

	public boolean isResolved() {
		for (int i=0;i<allGroups.length;i++) {
			if (allGroups[i].isResolved()==false) {
				return false;
			}
		}
		return true;


	}

	public int getRadix() {
		return radix;
	}

	public Object clone() throws CloneNotSupportedException  {
		return super.clone();
	}

}
